package org.grill.clovercash.accounts;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.grill.clovercash.CloverCashUIPlugin;
import org.grill.clovercash.storage.Reconciliation;

public class Account  {
	public enum Type {
		ASSET("Asset"),
		EXPENSE("Expense"),
		EQUITY("Equity"); 
		
		Type(String name) {
			this.name = name;
		}
		
		private String name;
		public String toString() {
			return name;
		}
		
		public static Type getType(String name) {
			if ("Expense".equals(name))
				return EXPENSE;
			if ("Equity".equals(name))
				return EQUITY;
			return ASSET;
		}
	}
	
	public Account(String name, String description, Type type) {
		this.name = name;
		this.description = description;
		this.type = type;
	}
	
	public Account(String name, String description, Type type, Account parent) {
		this.name = name;
		this.parent = parent;
		this.description = description;
		this.type = type;
		if (this.parent != null) { 
			parent.children.add(this);
			CloverCashUIPlugin.getDefault().getRootAccount().fireAdd(this);
		}
	}
	
	private void fireAdd(Account account) {
		for (IDeltaListener l : listeners) 
		{
			l.add(new DeltaEvent(this));
		}
	}

	public Account(String name) {
		this.name = name;
	}
	
	private ArrayList<Account> children = new ArrayList<Account>();
	private Account parent;
	
	String name = "";
	String description = "";
	
	private Reconciliation reconciliation = null;
	
	public void setReconciliation(Reconciliation rec) {
		this.reconciliation = rec;
	}
	
	public Reconciliation getReconciliation() {
		return reconciliation;
	}
	
	private ArrayList<Split> splits = new ArrayList<Split>();
	
	public BigDecimal getTotal() {
		BigDecimal total = new BigDecimal(0);
		for (Split s : splits) {
			total = total.add(s.value);
		}
		
		return total;
	}
	
	public BigDecimal getCumTotal() {
		BigDecimal total = getTotal();
		for (Account c : children)
			total = total.add(c.getCumTotal());
		return total;
	}
	
	public BigDecimal getReconciledTotal(boolean recurse) {
		BigDecimal total = new BigDecimal(0);
		for (Split s : splits)
			if (s.reconciled)
				total = total.add(s.value);
		
		if (recurse)
			for (Account c : children)
				total = total.add(c.getReconciledTotal(recurse));
		
		return total;
	}
	
	public static final String SEP = "/";
	
	public String getDisplayName() {
		if (parent == null)
			return name;
		if (parent.getParent() == null)
			return name;

		
		return parent.getDisplayName() + SEP + name;
	}
	
	public boolean isInHierarchy(Account a) {
		if (a == this)
			return true;
		for (Account c : children)
			if (c.isInHierarchy(a))
				return true;
					
		
		return false;
	}

	public String getName() {
		return name;
	}

	public List<Account> getChildren() {
		return children;
	}

	public Account getParent() {
		return parent;
	}

	public void removeListener(IDeltaListener l) {
		listeners.remove(l);
	}
	
	public void addListener(IDeltaListener l) {
		listeners.add(l);
	}

	private ArrayList<IDeltaListener> listeners = new ArrayList<IDeltaListener>();
	private Type type = Type.ASSET;
	
	public interface IDeltaListener {
		public void add(DeltaEvent event);
		public void remove(DeltaEvent event);
	}
	
	public class DeltaEvent {
		public Object data;
		public Object initiator;
		
		public DeltaEvent(Object data) {
			this.data = data;
		}
		
		public DeltaEvent(Object data, Object initiator) {
			this.data = data;
			this.initiator = initiator;
		}
	}

	public void remove(Account a) {
		children.remove(a);
		CloverCashUIPlugin.getDefault().getRootAccount().fireRemove(a);
	}

	private void fireRemove(Account a) {
		for (IDeltaListener l : listeners) 
		{
			l.remove(new DeltaEvent(a));
		}		
	}
	
	public void setDescription(String description) {
		this.description = description;
	}
	
	public String getDescription() {
		return description;
	}

	public void setType(Type type) {
		this.type  = type;
	}
	
	public Type getType() {
		return type;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<Split> getSplits() {
		return splits;
	}

	public List<Account> listAllChildren() {
		ArrayList<Account> allChildren = new ArrayList<Account>();
		fillChildren(allChildren);
		
		return allChildren;
	}

	private void fillChildren(ArrayList<Account> allChildren) {
		for (Account a : children) {
			allChildren.add(a);
			a.fillChildren(allChildren);
		}
	}

	public void changed(Transaction tx) {
		for (IDeltaListener l : listeners) {
			try {
				l.add(new DeltaEvent(tx));
			} catch (Exception e) { e.printStackTrace(); }
		}
		if (parent != null)
			try {
				CloverCashUIPlugin.getDefault().getRootAccount().changed(tx);
			} catch (Exception e) { e.printStackTrace(); }
	}

	public void setParent(Account parent) {
		this.parent = parent;
	}

	
	public Account findAccount(String accountName) {
		for (Account a : listAllChildren()) {
			if (a.getDisplayName().equals(accountName))
				return a;
		}
		return null;
	}
}
